package org.robert.export_client.easyexcel.write.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.robert.export_client.aop.ExcelDictAdapter;
import org.robert.export_client.config.executor.ExportExecutorFactory;
import org.robert.export_client.config.executor.ExportThreadPoolExecutor;
import org.robert.export_client.easyexcel.write.IExcelWriteService;
import org.robert.export_client.easyexcel.write.entity.ExcelResponse;
import org.robert.export_client.easyexcel.entity.WriteRequest;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author robert
 * @Date 2024/1/14 2:44
 **/
@Slf4j
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@EqualsAndHashCode(callSuper = true)
public class ExcelWriteDataService<T> extends WriteRequest<T> implements IExcelWriteService {

    private List<T> data;

    public static final ExportThreadPoolExecutor excelExportThreadPool
            = new ExportThreadPoolExecutor(1, 4, 60,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(200),
            new ExportExecutorFactory("excelExportData"));


    public ExcelWriteDataService(String path, List<T> data, Class<T> clazz){
        this.data = data;
        this.path = path;
        this.clazz = clazz;
    }

    public ExcelWriteDataService(String path, List<T> data, Class<T> clazz, Map<String, Map<String, String>> dictMap){
        this.data = data;
        this.path = path;
        this.clazz = clazz;
        this.dictMap = dictMap;
        if(org.apache.commons.collections4.MapUtils.isNotEmpty(dictMap)){
            this.checker = new ExcelDictAdapter<T>();
        }
    }

    public ExcelWriteDataService(String path, List<T> data, Class<T> clazz,
                                 Map<String, Map<String, String>> dictMap, String fileName, String sheetName){
        this.data = data;
        this.path = path;
        this.clazz = clazz;
        this.dictMap = dictMap;
        this.sheetName = sheetName;
        this.fileName = fileName;
        if(org.apache.commons.collections4.MapUtils.isNotEmpty(dictMap)){
            this.checker = new ExcelDictAdapter<T>();
        }
    }

    @Override
    public ExcelResponse exportToExcel(boolean isAsync) throws Exception {
        if(!check() || data == null){
            return new ExcelResponse("error", "参数异常");
        }
        Long taskWaitTime = 0L;
        if(isAsync){
            Runnable exportTask = this::execute;
            // 提交任务到线程池
            excelExportThreadPool.execute(exportTask);
            taskWaitTime = excelExportThreadPool.getTaskWaitTime(exportTask, 15 * 1000);
            log.info("Task: {}, wait time: {}", Thread.currentThread().getName(), taskWaitTime);
        }else{
            execute();
        }
        return new ExcelResponse(taskWaitTime);
    }

    private void execute(){
        // 字典转换
        try {
            if(MapUtils.isNotEmpty(dictMap) && CollectionUtils.isNotEmpty(data)){
                ExcelDictAdapter<T> checker = new ExcelDictAdapter<>();
                checker.setDict(data, dictMap);
            }
            String path = this.path + fileName + ".xlsx";
            long start = System.currentTimeMillis();
            try (ExcelWriter excelWriter = EasyExcel.write(path, clazz).build()) {
                WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
                excelWriter.write(data, writeSheet);
            }
            long endTime = System.currentTimeMillis() -start;
            log.info("execute run time: {} ms", endTime);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}
